package com.letv.core.parser;

import org.json.JSONException;
import org.json.JSONObject;

import android.text.TextUtils;

import com.letv.core.bean.LetvBaseBean;
import com.letv.core.network.volley.exception.DataIsErrException;
import com.letv.core.network.volley.exception.DataIsNullException;
import com.letv.core.network.volley.exception.DataNoUpdateException;
import com.letv.core.network.volley.exception.JsonCanNotParseException;
import com.letv.core.network.volley.exception.ParseException;
import com.letv.core.network.volley.exception.TokenLoseException;
import com.letv.core.utils.LogInfo;

/**
 * 接口数据解析基类
 * 
 * @param <T> bean
 * @param <D> 给parse方法的数据
 * @author zhuqiao
 * 
 */
public abstract class LetvBaseParser<T extends LetvBaseBean, D> extends CommonParser {
    /**
     * token失效错误码-1002
     */
    private static final String ERROR_CODE_1002 = "1002";

    /**
     * token失效错误码-1014
     */
    private static final String ERROR_CODE_1014 = "1014";

    /**
     * token失效错误码-1020
     */
    private static final String ERROR_CODE_1020 = "1020";

    /**
     * 验证评论token失效的result值
     */
    private static final String COMMENT_TOKEN_INVALID_RESULT = "notlogged";

    /**
     * 验证播放记录token失效的status值
     */
    private static final String PLAY_RECORD_TOKEN_INVALID_STATUS = "5";

    /**
     * 验证热点点赞token失效的code值
     */
    private static final String HOT_POINT_TOKEN_INVALID_CODE = "403";

    /**
     * 验证Credit token失效的code值
     */
    private static final String CREDIT_TOKEN_INVALID_CODE = "201";

    /**
     * 验证聊天室token失效result中的code值
     */
    private static final String CHATROOM_TOKEN_INVALID_RESULT_CODE = "1001";

    /**
     * 验证聊天室token失效的code值
     */
    private static final String CHATROOM_TOKEN_INVALID_CODE = "403";

    /**
     * 错误code
     */
    private int mErrCode;

    /**
     * 服务信息
     */
    private String mMessage;

    /**
     * 数据来源，区别解析,默认为0
     */
    private int mFrom;

    /**
     * bean class
     */
    protected Class<T> mClz;

    public LetvBaseParser(int from) {
        mFrom = from;
    }

    /**
     * 判断接口是否有更新.可由子类重写
     */
    public boolean hasUpdate() {
        return true;
    }

    /**
     * 开始解析
     * 
     * @param data 服务器数据
     * @return
     * @throws DataIsNullException
     * @throws DataIsErrException
     * @throws TokenLoseException
     * @throws ParseException
     * @throws JsonCanNotParseException
     * @throws DataNoUpdateException
     */
    public T doParse(String data) throws DataIsNullException, DataIsErrException, TokenLoseException, ParseException,
            JsonCanNotParseException, DataNoUpdateException {
        if (TextUtils.isEmpty(data)) {
            // 数据为空
            throw new DataIsNullException();
        }

        JSONObject object;
        try {
            object = new JSONObject(data);
        } catch (JSONException e) {
            // 不是json
            throw new DataIsErrException();
        }

        if (isTokenInvalid(object)) {
            // token失效
            throw new TokenLoseException();
        }

        if (canParse(data)) {
            // 经过验证可以解析
            D d = null;
            try {
                d = getData(data);
            } catch (Exception e) {
                // 数据出错
                throw new DataIsErrException();
            }

            if (d == null) {
                throw new ParseException();
            } else {
                try {
                    return parse(d);
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new ParseException();
                }
            }
        } else {
            if (hasUpdate()) {
                throw new JsonCanNotParseException();
            } else {
                throw new DataNoUpdateException();
            }
        }
    }

    /**
     * 解析数据
     * 
     * @param data
     * @return
     * @throws Exception
     */
    protected abstract T parse(D data) throws Exception;

    /**
     * 针对不同的接口类型（如：移动端接口，主站接口，支付接口等）进行不同实现， 如果独立接口，请实现为返回
     * true，否则不会进入解析方法，并抛出JsonCanNotParseException
     */
    protected abstract boolean canParse(String data);

    /**
     * 针对不同的接口类型，给parse方法吐出不同的数据
     * 
     * @param data 服务器数据
     * 
     * @return
     * @throws Exception
     */
    protected abstract D getData(String data) throws Exception;

    /**
     * 判断token是否失效
     * 
     * @param object
     * @return
     */
    public boolean isTokenInvalid(JSONObject object) {
        if (isChatRoomTokenInvalid(object) || isHotPointTokenInvalid(object) || isPlayRecordTokenInvalid(object)
                || isCommentTokenInvalid(object) || isCreditTokenInvalid(object)) {
            return true;
        }

        String errorCode = object.optString("errorCode");
        if (TextUtils.isEmpty(errorCode)) {
            return false;
        }

        if (TextUtils.equals(errorCode, ERROR_CODE_1002) && object.has("action")
                && TextUtils.isEmpty(object.optString("action"))) {
            return true;
        }

        return TextUtils.equals(errorCode, ERROR_CODE_1014) ||
                TextUtils.equals(errorCode, ERROR_CODE_1020);

    }

    /**
     * 判断评论token是否失效
     * <p>
     * {"header":{"status":"1"},"body":{"result":"notlogged","total":0,"rule":"" ,"data":[]}}
     * 
     * @param object
     * @return
     */
    private boolean isCommentTokenInvalid(JSONObject object) {
        boolean isInvalid = false;

        JSONObject body = object.optJSONObject("body");
        if (!isNull(body)) {
            String result = body.optString("result");
            if (TextUtils.equals(COMMENT_TOKEN_INVALID_RESULT, result)) {
                isInvalid = true;
            }
        }

        LogInfo.log("commentTokenInvalid", "isInvalid : " + isInvalid);
        return isInvalid;
    }

    /**
     * 判断播放记录token是否失效
     * 
     * @param object
     * @return
     */
    private boolean isPlayRecordTokenInvalid(JSONObject object) {
        boolean isInvalid = false;

        JSONObject header = object.optJSONObject("header");
        if (!isNull(header)) {
            String status = header.optString("status");
            if (TextUtils.equals(status, PLAY_RECORD_TOKEN_INVALID_STATUS)) {
                isInvalid = true;
            }
        }

        LogInfo.log("playRecordTokenInvalid", "isInvalid : " + isInvalid);
        return isInvalid;
    }

    /**
     * 判断热点点赞接口token是否失效
     * <p>
     * {"body":{"data":"用户未登录","code":403},"header":{"status":"1"}}
     * 
     * @param object
     * @return
     */
    private boolean isHotPointTokenInvalid(JSONObject object) {
        boolean isInvalid = false;

        JSONObject body = object.optJSONObject("body");
        if (!isNull(body)) {
            String code = body.optString("code");
            if (TextUtils.equals(code, HOT_POINT_TOKEN_INVALID_CODE)) {
                isInvalid = true;
            }
        }

        LogInfo.log("isHotPointTokenInvalid", "isInvalid : " + isInvalid);
        return isInvalid;
    }

    /**
     * 判断Credit token是否失效
     * 
     * @param object
     * @return
     */
    private boolean isCreditTokenInvalid(JSONObject object) {
        boolean isInvalid = false;

        JSONObject body = object.optJSONObject("body");
        if (!isNull(body)) {
            String code = body.optString("code");
            if (TextUtils.equals(code, CREDIT_TOKEN_INVALID_CODE)) {
                isInvalid = true;
            }
        }

        return isInvalid;
    }

    /**
     * 判断聊天室token是否失效
     * 
     * @param object
     * @return
     */
    private boolean isChatRoomTokenInvalid(JSONObject object) {
        boolean isInvalid = false;

        JSONObject body = object.optJSONObject("body");
        if (!isNull(body)) {
            JSONObject result = body.optJSONObject("result");
            if (!isNull(result)) {
                String resultCode = result.optString("code");
                if (TextUtils.equals(resultCode, CHATROOM_TOKEN_INVALID_RESULT_CODE)) {
                    isInvalid = true;
                }

                String code = body.optString("code");
                if (TextUtils.equals(code, CHATROOM_TOKEN_INVALID_CODE)) {
                    isInvalid = true;
                }
            }
        }

        return isInvalid;
    }

    /**
     * 得到错误信息id
     */
    public int getErrCode() {
        return mErrCode;
    }

    /**
     * 设置错误信息的id
     */
    protected void setErrCode(int errCode) {
        mErrCode = errCode;
    }

    /**
     * 设置服务器消息
     */
    protected void setMessage(String message) {
        mMessage = message;
    }

    /**
     * 得到服务器信息
     */
    public String getMessage() {
        return mMessage;
    }

    /**
     * 得到解析器数据来源，默认为0，不进行区别解析
     */
    public int getFrom() {
        return mFrom;
    }

    /**
     * 设置bean class
     * 
     * @param clz
     */
    public void setClz(Class<T> clz) {
        mClz = clz;
    }

}
